#!/usr/bin/python3
import sys
import fileinput
import re
from ParametersError import *
from File import FileWriter
import datetime


def about():
    print('\t\t\t\t\t本脚本')
    print('\t用来将两个文件按照特定列整合到一起的')
    print('\t##########\t文档说明\t##########')
    print('\t-1 -2：要输入的的文件')
    print('\t-o：要输出的文件或文件夹，若为文件，多个文件以逗号分隔')
    print('\t-by,-by.x,-by.y：指定要被merge的列，默认为1')
    print('\t-all,-all.x,-all.y 作用与R类似')
    exit()


def determine_keep(keep, keep_x, keep_y):
    if keep:
        return 'all'
    elif not keep and keep_x:
        return 'x'
    elif not keep and keep_y:
        return 'y'
    else:
        return None


def merge(input_file1, input_file2, output_file, num, keep=None, num_x=None, num_y=None):
    begin = datetime.datetime.now()
    print("程序开始于：%s" % begin)

    file1 = {}
    file2 = {}
    file1_flag = set()
    file2_flag = set()
    file1_length = 0

    def delete(li, index):
        return li[:index] + li[index + 1:]

    # 判断有没有特地指定用第几列，如果指定了，就设置好
    if num_x:
        lie = num_x
    else:
        lie = num

    with fileinput.input(input_file1) as f:
        for line in f:
            line = line.rstrip("\n")
            lines = re.split("\\s+", line)
            file1_length = len(lines)

            if lie >= len(lines):                                           # 一个预防措施，方式文件本身的问题
                print('设定列超出文件范围')
                exit()

            tem_line = delete(lines, lie)

            if lines[lie] not in file1_flag:                                # 读取文件，用一个以set为值的字典收集所有的文件内容
                tem = set()
                if len(tem_line) > 1:                                       # 将每行文件分割之后，如果有多个，就用\t分隔，形成一个字符串
                    tem.add('\t'.join(tem_line))
                else:
                    tem = set(tem_line)
                file1_flag.add(lines[lie])
                file1.update({lines[lie]: tem})
            else:
                tem = set()
                if len(tem_line) > 1:
                    tem.add('\t'.join(tem_line))
                else:
                    tem = set(tem_line)
                tem1 = file1.get(lines[lie])
                tem1.union(tem)
                file1.update({lines[lie]: tem1})

    if num_y:
        lie = num_y
    else:
        lie = num

    with fileinput.input(input_file2) as f:
        for line in f:
            line = line.rstrip("\n")
            lines = re.split("\\s+", line)
            tem_line = delete(lines, lie)

            if lie >= len(lines):
                print('设定列超出文件范围')
                exit()

            if lines[lie] not in file2_flag:
                tem = set()
                if len(tem_line) > 1:
                    tem.add('\t'.join(tem_line))
                else:
                    tem = set(tem_line)
                file2_flag.add(lines[lie])
                file2.update({lines[lie]: tem})
            else:
                tem = set()
                if len(tem_line) > 1:
                    tem.add('\t'.join(tem_line))
                else:
                    tem = set(tem_line)
                tem1 = file2.get(lines[lie])
                tem1.union(tem)
                file2.update({lines[lie]: tem1})

    common = list(file1_flag.intersection(file2_flag))                        # 返回两个set中共有的元素
    only_x = list(file1_flag - file2_flag)                                   # 返回单独只在两个文件中存在的那些
    only_y = list(file2_flag - file1_flag)

    with FileWriter(output_file) as w:
        for flag in common:
            tem1 = list(file1.get(flag))
            tem2 = list(file2.get(flag))

            for i in tem1:
                for j in tem2:                                              # 嵌套循环，用来写出文件
                    w.write(flag + "\t" + i + "\t" + j + "\n")

        if keep == 'all':
            for i in only_x:
                tem = list(file1.get(i))
                for j in tem:
                    w.write(i + "\t" + j + "\n")
            for i in only_y:
                tem = list(file2.get(i))
                for j in tem:
                    w.write(i + "\t" + '\t\t' * (file1_length-1) + j + "\n")
        elif keep == 'x':
            for i in only_x:
                tem = list(file1.get(i))
                for j in tem:
                    w.write(i + "\t" + j + "\n")
        elif keep == 'y':
            for i in only_y:
                tem = list(file2.get(i))
                for j in tem:
                    w.write('\t\t' * file1_length + i + "\t" + j + "\n")
    end = datetime.datetime.now()
    print("程序终止于：%s" % end)
    print("一共花费：%s" % str(end - begin))

if __name__ == '__main__':
    parameters = {}  # 用来读取命令行参数的，遍历所有参数，开头以-开始的，下一个就作为参数附加，然后统一添加到一个词典中，再提取出来
    if len(sys.argv) <= 1:
        about()

    try:
        for i in range(len(sys.argv)):
            if sys.argv[i] == '-h' or sys.argv[i] == '--help':
                about()
            if sys.argv[i].startswith('-'):
                parameters.update({sys.argv[i]: sys.argv[i + 1]})
            elif sys.argv[i].startswith('--'):
                parameters.update({sys.argv[i]: sys.argv[i + 1]})
    except IndexError:  # 判断参数是否输入有误
        print("输入的参数有误")
        exit()
    try:
        if '-1' in parameters.keys():
            input_file1 = parameters.get('-1')
        raise_file(input_file1)

        if '-2' in parameters.keys():
            input_file2 = parameters.get('-2')
        raise_file(input_file2)

        if '-o' in parameters.keys():
            output_file = parameters.get('-o')
        raise_file(output_file)

        keep_all = False
        if '-all' in parameters.keys():
            keep_all = parameters.get('-all')
        keep_all = raise_bool(keep_all)

        keep_x = False
        if '-all.x' in parameters.keys():
            keep_x = parameters.get('-all.x')
        keep_x = raise_bool(keep_x)

        keep_y = False
        if '-all.y' in parameters.keys():
            keep_y = parameters.get('-all.y')
        keep_y = raise_bool(keep_y)

        lie=0                                                   # 总体的none初始化为0，跟后边的两个不一样，因为，
        if '-by' in parameters.keys():                          # 后边两个要用，肯定会初始化，这个不管怎样都是要用的
            lie = parameters.get('-by')
        lie = raise_int(lie)

        lie_x=None
        if '-by.x' in parameters.keys():
            lie_x = parameters.get('-by.x')

        lie_y=None
        if '-by.y' in parameters.keys():
            lie_y = parameters.get('-by.y')

        keep = determine_keep(keep=keep_all, keep_x=keep_x, keep_y=keep_y)
        merge(input_file1=input_file1, input_file2=input_file2, output_file=output_file, num=lie, num_x=lie_x, num_y=lie_y, keep=keep)

    except ParametersError as e:
        print(e.value)

    input('任意键退出')
